package client_gui;

import java.awt.AWTException;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import parameters.RLM_Parameters;
import utils.Constants;
import utils.ImageCreator;
import actions.RLMActionManager;
import client.ClientApplication;
import client_tree.ContactsTree;
import client_tree.User;


/**
 * Klasa glavnog prozora client aplikacije.
 * 
 * @author UrosKrkic & Radivoje Popovic
 */
public class ClientWindow extends JFrame implements Constants {

	private static final long serialVersionUID = 1L;
	

	/**
	 * Referenca na objekat aplikacije.
	 */
	private ClientApplication theApp;
	
	
	// karakteristike prozora
	private String title = "RAF Live Messenger - v2.0";
	private int width = CLIENT_WIDTH;
	private int height = CLIENT_HEIGHT;
	private boolean resizable = true;
	private boolean alwaysOntTop = false;

//	private boolean screenFlag = false;
	
	private String fontName;
	private int fontStyle;
	private int fontSize;
	private Color fontColor;
	private Color backgroundColor;
	
	/**
	 * Objekat koji upravlja dogadjajima samog prozora.
	 */
	private ClientWindowHandler windowHandler;

	
	private Toolkit kit;
	
	
	private JPanel jContentPane = null;

	private JMenuBar jJMenuBar = null;
	
	private JMenu fileMenu = null;
	private JMenu actionsMenu = null;
	private JMenu toolsMenu = null;
	private JMenu helpMenu = null;
	
	
	/**
	 * Upravlja akcijama GUI-a.
	 */
	private RLMActionManager actionManager = null;
	
	
	/**
	 * Panel za logovanje korisnika - startup panel.
	 */
	private InitialPanel initialPanel = null;
	

	/**
	 * Panel logovanog korisnika.
	 */
	private LoggedPanel loggedPanel = null;
	
	
	/**
	 * Kontekstni menu koji se otvara iz stabla korisnika.
	 */
	private JPopupMenu jContextMenu = null;
	
	
	/**
	 * Kontekstni menu za promenu statusa logovanog korisnika.
	 */
	private JPopupMenu statusContextMenu = null;

	
	// Stavke kontekstnog menija za promenu statusa.
	private StatusContextItem onlineItem = null;
	private StatusContextItem awayItem = null;
	private StatusContextItem busyItem = null;
	private StatusContextItem invisibleItem = null;
	
	
	/**
	 * Novi status setovan izoborom stavke iz ContextMenija.
	 */
	private int newStatus = -1;
	
		

	/**
	 * Konstruktor.
	 * @param theApp - referenca na objekat aplikacije
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public ClientWindow(ClientApplication theApp) {
		super();
		
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e1) {
			e1.printStackTrace();
		} catch (InstantiationException e1) {
			e1.printStackTrace();
		} catch (IllegalAccessException e1) {
			e1.printStackTrace();
		} catch (UnsupportedLookAndFeelException e1) {
			e1.printStackTrace();
		}
		
		this.theApp = theApp;
		
		windowHandler = new ClientWindowHandler(this);
		actionManager = new RLMActionManager(this);
		
		initialize();
		
		try {
			sysTrayCreator();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}

	
	public void showSplashScreen() {
		if ( RLM_Parameters.isSplashScreen() == true ) {
			SplashScreenDialog splashScreen = new SplashScreenDialog(this);
			splashScreen.setVisible(true);
		}
	}
	
	
	/**
	 * Metod vrsi inicijalizaciju GUI-a aplikacije.
	 * @author UrosKrkic & Radivoje Popovic
	 */
	private void initialize() {
		this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		this.setJMenuBar(getJJMenuBar());
		this.addWindowListener(windowHandler);
		
		kit = this.getToolkit();
		Dimension dim = kit.getScreenSize();
		this.setLocation( (dim.width-width)/2, (dim.height-height)/2 );
		
		this.setSize(width, height);
		this.setResizable(resizable);
		this.setTitle(title);
		this.setAlwaysOnTop(alwaysOntTop);
		
		this.createContextMenu();
		
		this.createStatusContextMenu();
		
		this.setContentPane(getJContentPane());
		
		// prikazivanje odgovarajuceg panela iz CardLayout manager-a
		if (getApplicaton().getState() == INITIAL_STATE) {
			((CardLayout)jContentPane.getLayout()).show(jContentPane, "initial");
		}
		else {
			((CardLayout)jContentPane.getLayout()).show(jContentPane, "logged");
		}

		// setovanje ikonice prozora
		URL url = ClientWindow.class.getResource("/client_gui/client_icon.png");
		this.setIconImage(kit.createImage(url));
		
		// osvezavanje contentPane-a
		SwingUtilities.updateComponentTreeUI(jContentPane);
	}

	
	
	/**
	 * Metod vrsi osvezavanje prozora aplikacije, prilikom promene stanja klijenta.
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public void refreshWindow() {
		if (getApplicaton().getState() == INITIAL_STATE) {
			((CardLayout)jContentPane.getLayout()).show(jContentPane, "initial");
		}
		else {
			((CardLayout)jContentPane.getLayout()).show(jContentPane, "logged");
		}
	
//		SwingUtilities.updateComponentTreeUI(jContentPane);
		
		actionManager.setRights();
		
		refreshTree();
		
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				SwingUtilities.updateComponentTreeUI(jContentPane);
			}
		});
	}
	

	
	/**
	 * Metod osvezava ContactsTree komponentu, tj. stablo sa korisnicima (viewer).
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public void refreshTree() {
		loggedPanel.getContactsPanel().getTree().refreshTree();
	}
	
	
	/**
	 * Metod vraca referencu na stablo sa korisnicima.
	 * @return - contact list tree
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public ContactsTree getTree() {
		return loggedPanel.getContactsPanel().getTree();
	}
	
	
	/**
	 * Inicijalizacija jContentPane-a.
	 * Kao layout manager setuje se CardLayout manager, koji skladisti dva panela,
	 * startup panel i panel logovanog korisnika. U zavisnosti od stanja aplikacije,
	 * prikazuje se odgovarajuci panel.
	 * @return JPanel jContentPane
	 * @author UrosKrkic & Radivoje Popovic
	 */
	private JPanel getJContentPane() {
		if (jContentPane == null) {
			jContentPane = new JPanel();
			jContentPane.setLayout(new CardLayout());
			
			// dodavanje panela, sa ogranicenjima, kojima se identifikuje komponenta
			// u CardLayout manager-u
			jContentPane.add(getInitialPanel(), "initial");			
			jContentPane.add(getLoggedPanel(), "logged");
		}
		return jContentPane;
	}

	
	
	/**
	 * Metod vraca referencu na menager akcija GUI komponenti.
	 * @return actionManager
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public RLMActionManager getActionManager() {
		return actionManager;
	}

	
	/**
	 * Metod vraca referencu na objekat aplikacije. Ovo omogucava pristup objektu
	 * aplikacije panelima i komponentama ciji je owner glavni prozor aplikacije.
	 * @return Application referenca
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public ClientApplication getApplicaton() {
		return this.theApp;
	}
	
	
	
	/**
	 * Metoda vraca glavni konteksni meni koji se primenjuje na elemente stabla korisnika.
	 * @return - jContextMenu
	 * @author UrosKrkic & Radivoje Popovic
	 */
	private void createContextMenu() {
		if (jContextMenu == null) {
			jContextMenu = new JPopupMenu();
			
			jContextMenu.add(actionManager.getSendMessageAction());
			jContextMenu.add(actionManager.getSendFileAction());
			jContextMenu.addSeparator();
			jContextMenu.add(actionManager.getAudioCallAction());
			jContextMenu.add(actionManager.getVideoCallAction());
			jContextMenu.addSeparator();
			jContextMenu.add(actionManager.getDeleteUserAction());
			jContextMenu.add(actionManager.getBlockUserAction());
			jContextMenu.add(actionManager.getUnblockUserAction());
			jContextMenu.addSeparator();
			jContextMenu.add(actionManager.getDetailsUserAction());
		}
	}
	
	
	/**
	 * Vraca referencu na contextMenu, kako bi mogao da se prikaze iz stabla korisnika,
	 * tj. iz metoda koje obradjuju dogadjaj misa.
	 * @return - referenca na contextMenu
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public JPopupMenu getContexMenu() {
		return this.jContextMenu;
	}
	
	
	/**
	 * Metod postavlja username, password i status iz Login panela kao atribute
	 * ClientUser objekta, koji predstavlja korisnika koji je pokrenuo klijent
	 * aplikaciju i koji zeli da se loguje. 
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public boolean createPartialLoginInfo() {
		return initialPanel.createPartialLoginInfo();
	}
	
	
	/**
	 * Metod postavlja avatar.
	 * @param avatar - novi avatar
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public void setAvatar(String avatar) {
		loggedPanel.setAvatar(avatar);
	}
	
	
	/**
	 * Metod postavlja nickname.
	 * @param nickname - novi nickname
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public void setNickname(String nickname) {
		loggedPanel.setNickname(nickname);
	}
	
	
	/**
	 * Metod postavlja status.
	 * @param status - novi status
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public void setStatus(int status) {
		loggedPanel.setStatus(status);
	}
	
	
	
	// Metode vrse inicijalizaciju GUI komponenti.
	
	/**
	 * This method initializes jJMenuBar	
	 * 	
	 * @return javax.swing.JMenuBar	
	 */
	private JMenuBar getJJMenuBar() {
		if (jJMenuBar == null) {
			jJMenuBar = new JMenuBar();
			jJMenuBar.add(getFileMenu());
			jJMenuBar.add(getActionsMenu());
			jJMenuBar.add(getToolsMenu());
			jJMenuBar.add(getHelpMenu());
		}
		return jJMenuBar;
	}

	

	private JMenu getFileMenu() {
		if (fileMenu == null) {
			fileMenu = new JMenu();
			fileMenu.setText("File");
			fileMenu.setMnemonic('f');
			
			fileMenu.add(actionManager.getLogoutAction());
			fileMenu.addSeparator();
			fileMenu.add(actionManager.getUnregisterAction());
			fileMenu.addSeparator();
			fileMenu.add(actionManager.getExitAction());
		}
		return fileMenu;
	}
	
	
	private JMenu getActionsMenu() {
		if (actionsMenu == null) {
			actionsMenu = new JMenu();
			actionsMenu.setText("Actions");
			actionsMenu.setMnemonic('a');
			
			actionsMenu.add(actionManager.getSendMessageAction());
			actionsMenu.add(actionManager.getSendFileAction());
			actionsMenu.addSeparator();
			actionsMenu.add(actionManager.getAudioCallAction());
			actionsMenu.add(actionManager.getVideoCallAction());
			actionsMenu.addSeparator();
			actionsMenu.add(actionManager.getDeleteUserAction());
			actionsMenu.add(actionManager.getBlockUserAction());
			actionsMenu.add(actionManager.getUnblockUserAction());
			actionsMenu.addSeparator();
			actionsMenu.add(actionManager.getFindUserAction());
			actionsMenu.addSeparator();
			actionsMenu.add(actionManager.getDetailsUserAction());
		}
		
		return actionsMenu;
	}

	
	private JMenu getToolsMenu() {
		if (toolsMenu == null) {
			toolsMenu = new JMenu();
			toolsMenu.setText("Tools");
			toolsMenu.setMnemonic('t');
			
			toolsMenu.add(actionManager.getAlwaysOnTopAction());
			toolsMenu.add(actionManager.getDefaultPositionAndSize());
			toolsMenu.addSeparator();
			toolsMenu.add(actionManager.getChangeEmailAction());
			toolsMenu.add(actionManager.getChangePasswordAction());
			toolsMenu.addSeparator();
			toolsMenu.add(actionManager.getBlockListAction());
			toolsMenu.add(actionManager.getMyDetailsAction());
			toolsMenu.addSeparator();
			toolsMenu.add(actionManager.getOptionsAction());
			toolsMenu.add(actionManager.getStreamingSettingsAction());
		}
		
		return toolsMenu;
	}

	
	private JMenu getHelpMenu() {
		if (helpMenu == null) {
			helpMenu = new JMenu();
			helpMenu.setText("Help");
			helpMenu.setMnemonic('h');
			
			helpMenu.add(actionManager.getHelpAction());
			helpMenu.add(actionManager.getSplashScreenAction());
			helpMenu.add(actionManager.getAboutAction());
		}
		
		return helpMenu;
	}

	
	private LoggedPanel getLoggedPanel() {
		if (loggedPanel == null) {
			loggedPanel = new LoggedPanel(this);
		}
		
		return loggedPanel;
	}
	
	
	private InitialPanel getInitialPanel() {
		if (initialPanel == null) {
			initialPanel = new InitialPanel(this);
		}
		
		return initialPanel;
	}
	
	
	
	/**
	 * Metod kreira i inicijalizuje popup menu za promenu statusa.
	 * @return
	 */
	private void createStatusContextMenu() {
		if (statusContextMenu == null) {
			statusContextMenu = new JPopupMenu();
			
			createStatusItems();
			
			statusContextMenu.add(onlineItem);
			statusContextMenu.add(busyItem);
			statusContextMenu.add(awayItem);
			statusContextMenu.add(invisibleItem);
		}
	}
	
	
	
	/**
	 * Metod kreira stavka popup menija za promenu statusa.
	 * @author UrosKrkic & Radivoje Popovic
	 */
	private void createStatusItems() {
		if (onlineItem == null) {
			onlineItem = new StatusContextItem(ONLINE_STATUS);
		}

		if (awayItem == null) {
			awayItem = new StatusContextItem(AWAY_STATUS);
		}
		
		if (busyItem == null) {
			busyItem = new StatusContextItem(BUSY_STATUS);
		}
		
		if (invisibleItem == null) {
			invisibleItem = new StatusContextItem(INVISIBLE_STATUS);
		}
	}
	
	
	
	/**
	 * Metod vraca referencu na popup menu za promenu statusa.
	 * @return - popup za promenu statusa
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public JPopupMenu getStatusContexMenu() {
		return this.statusContextMenu;
	}
	
	
	/**
	 * Privatna klasa koja obradjuje dogadjaje na item-e Popup menija za promenu statusa.
	 * @author UrosKrkic & Radivoje Popovic
	 */
	private class StatusContextItem extends JMenuItem {
		
		private int statusCode;
		
		public StatusContextItem(int status) {
			this.statusCode = status;
			this.setText(STATUS_NAMES[status]);
			this.setIcon(ImageCreator.createImageIcon(ClientWindow.class, "/status_images/" + STATUS_NAMES[status] + ".png"));
			this.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					if (theApp.getState() == LOGGED_STATE) {
						
						newStatus = statusCode;
						
						
						JButton button = new JButton(actionManager.getChangeStatusAction());
						button.doClick();
						
					}
					else {
						initialPanel.setInitialStatus(STATUS_NAMES[statusCode]);
						setTrayIcon(statusCode);
					}
				}
			});
		}
	}

	
	
	/**
	 * Metod vraca novi status setovan izborom stavke iz ContexMenija.
	 * @return - novi status
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public int getNewStatus() {
		return this.newStatus;
	}
	
	
	public InitialPanel getWindowInitialPanel() {
		return this.initialPanel;
	}
	

	public void setInitialStatus(String status) {
		initialPanel.setInitialStatus(status);
	}

	public void setLoginUsername(String username) {
		initialPanel.setLoginUsername(username);
	}
	
	public void setLoginPassword(String password) {
		initialPanel.setLoginPassword(password);
	}
	
	public void setUsernameCheckBox(boolean flag) {
		initialPanel.setUsernameCheckBox(flag);
	}
	
	public void setPasswordCheckBox(boolean flag) {
		initialPanel.setPasswordCheckBox(flag);
	}
	
	public boolean isUsernameCheckBoxSelected() {
		return initialPanel.isUsernameCheckBoxSelected();
	}
	
	public boolean isPasswordCheckBoxSelected() {
		return initialPanel.isPasswordCheckBoxSelected();
	}
	
	public User getSelectedUser() {
		return loggedPanel.getContactsPanel().getSelectedUser();
	}


	public Color getBackgroundColor() {
		return backgroundColor;
	}


	public void setBackgroundColor(Color backgroundColor) {
		this.backgroundColor = backgroundColor;
	}


	public Color getFontColor() {
		return fontColor;
	}


	public void setFontColor(Color fontColor) {
		this.fontColor = fontColor;
	}


	public String getFontName() {
		return fontName;
	}


	public void setFontName(String fontName) {
		this.fontName = fontName;
	}


	public int getFontSize() {
		return fontSize;
	}


	public void setFontSize(int fontSize) {
		this.fontSize = fontSize;
	}


	public int getFontStyle() {
		return fontStyle;
	}


	public void setFontStyle(int fontStyle) {
		this.fontStyle = fontStyle;
	}
	
	
//	public boolean getScreenFlag() {
//		return screenFlag;
//	}
//
//
//	public void setScreenFlag(boolean screenFlag) {
//		this.screenFlag = screenFlag;
//	}
	
	
	/* System Tray Section */
	
	private SystemTray tray = null;
	private TrayIcon trayIcon = null;
	private PopupMenu trayPopup = null;
	
	public void setTrayIcon(int status) {
		if ( getApplicaton().getState() == LOGGED_STATE ) {
			ImageIcon icon = ImageCreator.createImageIcon(ClientWindow.class, "/status_images/" + STATUS_NAMES[status] + ".png");
			trayIcon.setImage(icon.getImage());
		}
	}

	
	private PopupMenu getTrayPopup() {
		if ( trayPopup == null ) {
			trayPopup = new PopupMenu();

			trayPopup.add(actionManager.getOptionsAction().getItem());
			trayPopup.add(actionManager.getStreamingSettingsAction().getItem());
			trayPopup.addSeparator();
			trayPopup.add(actionManager.getAboutAction().getItem());
			trayPopup.addSeparator();
			trayPopup.add(actionManager.getLogoutAction().getItem());
			trayPopup.addSeparator();
			trayPopup.add(actionManager.getExitAction().getItem());	
		}
		return trayPopup;
	}
	
	private void sysTrayCreator() throws Exception {

		if ( !SystemTray.isSupported() ) {
			System.out.println("YES");
		}

		tray = SystemTray.getSystemTray();

		trayIcon = new TrayIcon(ImageCreator.createImageIcon(ClientWindow.class, "/status_images/" + STATUS_NAMES[OFFLINE_STATUS] + ".png").getImage(), "RLM", getTrayPopup());
		
		setTrayIcon(OFFLINE_STATUS);
		
		trayIcon.setImageAutoSize(true);
		
		trayIcon.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				if (e.getClickCount() == 2) {
					ClientWindow.this.setVisible(true);
				}
			}
		});

		if (tray != null) {
			try {
				tray.add(trayIcon);
			} catch (AWTException e1) {
				e1.printStackTrace();
			}
		}
	}
	
}
